perm filename PROTO1.UNI[P,JRA] blob
sn#151969 filedate 1975-03-21 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00002 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002
C00025 ENDMK
C⊗;
to write unify(x,y) where x and y are sequences containing variables, constants
or functional terms. The mgu is returned if x and y are unifable; the mgu is
either empty or a sequence of pairs (of substitutions), such that application
of the substitutions to x and y results in identical expressions; if x and y
are not unifiable the atom LOSE is returned.
want double loop on x and y.
istermseq(x)∧istermseq(y)
{A;R; while ¬empty[x]∧ ¬empty[y] do B;x←rest[x]; y← rest[y]}
(z=LOSE∧ ¬unifiable(x,y))∨mgunified(z,x,y)
using V4 machine should generate:
istermseq(x)∧istermseq(y){A}R;
R∧(¬empty[x]∧¬empty[y]){B;x←rest[x]; y←rest[y]}R
R∧¬(¬empty[x]∧¬empty[y])⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
-------------------------------------------
istermseq(x)∧istermseq(y)
{A;R; while ¬empty[x]∧ ¬empty[y] do B;x←rest[x]; y← rest[y]}
(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
and expand it (using V1) to:
istermseq(x)∧istermseq(y){A}R(x,y);
R(x,y)∧(¬empty[x]∧¬empty[y]){B}R(rest[x],rest[y]);
R(x,y)∧¬(¬empty[x]∧¬empty[y])⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
-------------------------------------------
istermseq(x)∧istermseq(y)
{A;R(x,y); while ¬empty[x]∧ ¬empty[y] do B;x←rest[x]; y← rest[y]}
(z=LOSE∧ ¬unifible(x,y))∨ mgunified(z,x,y)
woops! want new variable to contain substitution being built.
want z←NIL followed by loop. machine regroups and does:
istermseq(x)∧istermseq(y){z←()}R(x,y,z); (1)
R(x,y,z)∧(¬empty[x]∧¬empty[y]){B}R(rest[x],rest[y],z); (2)
R(x,y,z)∧¬(¬empty[x]∧¬empty[y])⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)(3)
-------------------------------------------
istermseq(x)∧istermseq(y)
{z←();R(x,y,z); while ¬empty[x]∧ ¬empty[y] do B;x←rest[x]; y← rest[y]}
(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
Since (3) above is a put implication, perhaps we should attempt to
specify the invariant, R.
Well it's that z applied to the initial segments of x and y unify them.
So our loop must save the inputs say in x0 and y0.
Not necessarily: it is only to initial segments of the inputs which are
of interest.
Observation: at first glance the easiest way to specify invariant
is in terms of two variables say x1, and y1 which contain the initial segments
of x and y and are constructed during the program(by concat). The ONLY reason
for having x1 and y1 is for assertions. Then besides assertions being added
to program we might also add program.(later I was told that this hack is called
virtual program)
So:
istermseq(x)∧istermseq(y)∧istermseq(x1)∧istermseq(y1)∧(issub(z)∨z=LOSE)
{x1←();y1←();z←()}
R(x,x1,y,y1,z) (1)
R(x,x1,y,y1,z)∧(¬empty[x]∧¬empty[y])
{B;x1←concat[first[x];x1];y1← concat[first[y];y1]}
R(rest[x],x1,rest[y],y1,z); (2)
R(x,x1,y,y1,z)∧¬(¬empty[x]∧¬empty[y])⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)(3)
-------------------------------------------
istermseq(x)∧istermseq(y)∧istermseq(x1)∧istermseq(y1)∧(issub(z)∨z=LOSE)
{x1←();
y1←();
z←();R(x,x1,y,y1,z);
while ¬empty[x]∧ ¬empty[y] do B;
x1← concat[first[x];x1]; y1← concat[first[y];y1];
x←rest[x]; y← rest[y]}
(z=LOSE∧ ¬unifiable(x,y))∨ unified(z,x,y)
Things are getting complicated, but are still manageable. We should
finish off the invariant.
Using V1 and V3 we can simplfy (1):
istermseq(x)∧istermseq(y)∧istermseq(x1)∧istermseq(y1)∧(issub(z)∨z=LOSE)
⊃
R(x,(),y,(),()) (1)
Similarly using V1 on (2):
R(x,x1,y,y1,z)∧(¬empty[x]∧¬empty[y])
{B}
R(rest[x],concat[first[x];x1],rest[y],concat[first[y];y1],z); (2)
also (3) will simplify slightly:
R(x,x1,y,y1,z)∧¬(¬empty[x]∧¬empty[y])⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
So let us pick R(x,x1,y,y1,z) as:
istermseq(x)∧istermseq(y)∧istermseq(x1)∧istermseq(y1)∧(issub(z)
∧....
** troubles, time to regroup. We wish to say that append[x1;x] is the original
** termlist, but we can't since termlist is being destroyed.
** so we must save it. Similarly for y. We use x2 and y2 for destruction.
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)∧
∧istermseq(x2)∧istermseq(y2)∧(issub(z)∨z=LOSE)
{x1←();y1←();x2←x;y2←y;z←()}
R(x,x1,x2,y,y1,y2,z) (1)
R(x,x1,x2,y,y1,y2,z)∧(¬empty[x2]∧¬empty[y2])
{B;x1←concat[first[x2];x1];y1← concat[first[y2];y1]}
R(x,x1,rest[x2],y,y1,rest[y2],z); (2)
R(x,x1,x2,y,y1,y2,z)∧¬(¬empty[x2]∧¬empty[y2])⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)(3)
-------------------------------------------
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)∧
∧istermseq(x2)∧istermseq(y2)∧(issub(z)∨z=LOSE)
{x1←();
x2←x;
y1←();
y2←y;
z←();R(x,x1,x2,y,y1,y2,z);
while ¬empty[x2]∧ ¬empty[y2] do B;
x1← concat[first[x2];x1]; y1← concat[first[y2];y1];
x2←rest[x2]; y2← rest[y2]}
(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
Now, back to R(x,x1,x2,y,y1,y2,z)
New (1) simplifies:
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)∧
∧istermseq(x2)∧istermseq(y2)∧(issub(z)∨z=LOSE)
⊃
R(x,(),x,y,(),y,())
So does (2):
R(x,x1,x2,y,y1,y2,z)∧(¬empty[x2]∧¬empty[y2])
{B}
R(x,concat[first[x2];x1],rest[x2],y,concat[first[y2];y1],rest[y2],z)
and a slightly simplified (3)
R(x,x1,x2,y,y1,y2,z)∧(empty[x2]∨empty[y2])
⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
So try again for R(x,x1,x2,y,y1,y2,z):
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)
∧istermseq(x2)∧istermseq(y2)
∧((issub(z)∧x=append[x1;x2]∧y=append[y1;y2]∧mgunified(z;x1;y1))
∨(z=LOSE∧¬unifiable(x,y)
)
This R makes (1) true. (using properties of append and mgunified and issub
***make the properties explicit****
Look at (3):
R(x,x1,x2,y,y1,y2,z)∧(empty[x2]∨empty[y2])
⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
istermseq(())∧istermseq(())
∧istermseq(x1)∧istermseq(y1)
∧istermseq(x2)∧istermseq(y2)
∧((issub(z)∧x=append[x1;()]∧y=append[y1;()]∧mgunified(z;x1;y1))
∨(z=LOSE∧¬unifiable(x,y)
)
⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
**mumble ok.**doit
now (2)
R(x,x1,x2,y,y1,y2,z)∧(¬empty[x2]∧¬empty[y2])
{B}
R(x,concat[first[x2];x1],rest[x2],y,concat[first[y2];y1],rest[y2],z)
Before going off to write {B} we should try to tighten up the
outer loops: namely there is no point to bother with {B} if z is LOSE.
So we wish to modify the termination on "while" to exit if LOSE is
given to z as value.
This results in:
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)∧
∧istermseq(x2)∧istermseq(y2)∧(issub(z)∨z=LOSE)
⊃
R(x,(),x,y,(),y,())
R(x,x1,x2,y,y1,y2,z)∧(¬empty[x2]∧¬empty[y2]∧¬z=LOSE)
{B}
R(x,concat[first[x2];x1],rest[x2],y,concat[first[y2];y1],rest[y2],z)
R(x,x1,x2,y,y1,y2,z)∧(empty[x2]∨empty[y2]∨z=LOSE)
⊃(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
_________________________________________________________
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)∧
∧istermseq(x2)∧istermseq(y2)∧(issub(z)∨z=LOSE)
{x1←();
x2←x;
y1←();
y2←y;
z←();R(x,x1,x2,y,y1,y2,z);
while ¬empty[x2]∧ ¬empty[y2]∧¬z=LOSE do B;
x1← concat[first[x2];x1]; y1← concat[first[y2];y1];
x2←rest[x2]; y2← rest[y2]}
(z=LOSE∧ ¬unifiable(x,y))∨ mgunified(z,x,y)
Now we are in reasonable shape: the outer loops are coded and
the inner structure, represented by "{B}" is isolated, its
I/O requirements are clear(?: we will see!!). Let's expand (2) using R
istermseq(x)∧istermseq(y)
∧istermseq(x1)∧istermseq(y1)
∧istermseq(x2)∧istermseq(y2)
∧((issub(z)∧x=append[x1;x2]∧y=append[y1;y2]∧mgunified(z;x1;y1))
∨(z=LOSE∧¬unifiable(x1,y1)
)
∧(¬empty[x2]∧¬empty[y2] ∧¬z=LOSE)
{B}
istermseq(x)∧istermseq(y)
∧istermseq(concat[first[x2];x1])∧istermseq(concat[first[y2];y1])
∧istermseq(rest[x2])∧istermseq(rest[y2])
∧((issub(z)∧x=append[concat[first[x2];x1];rest[x2]]
∧y=append[concat[first[y2];y1];rest[y2]]
∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Simplifications are rampant( i.e. making assumptions "global;
properties of istermseq, etc.):
issub(z)∧x=append[x1;x2]∧y=append[y1;y2]∧mgunified(z;x1;y1)
{B}
∧((issub(z)∧x=append[concat[first[x2];x1];rest[x2]]
∧y=append[concat[first[y2];y1];rest[y2]]
∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Using properties of append and concat:
issub(z)∧mgunified(z;x1;y1)
{B}
((issub(z)∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Expand "{B}" to return new value of z, either substitution unifying
first elements of x2 and y2 or returning LOSE if not possible:
issub(z)∧mgunified(z;x1;y1)
{C;z←unify1[first[x2];first[y2];z]}
((issub(z)∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
By V1 gives:
issub(z)∧mgunified(z;x1;y1)
{C}
((issub(unify1[first[x2];first[y2];z])
∧mgunified(unify1[first[x2];first[y2];z];concat[first[x2];x1];concat[first[y2];y1]))
∨(unify1[first[x2];first[y2];z]=LOSE
∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
After unify1[x;y;z]:
x is a term; y is a term; z is a substitution;
isterm(x)∧isterm(y)∧issub(z)
if, after application of the substitution z, the transformed terms x and y
are unifiable, then we will return that necessary substitution. If unification
is not posible we return LOSE.
Try it: V8;
issub(z)∧isterm(x)∧isterm(y){z:unify1[x;y;z];A}issub(z)∧mgunif_term(x,y,compose **
****troubles: z before and after.
** decision: should we go in with substitutions already made?
** there is a related decision which we have to make: how to update the subsitution.
** this could give the following:
issub(z)∧mgunified(z;x1;y1)
{C;z1←unify1[subst[first[x2];z];subst[first[y2];z]]
if issub(z1) then z ← compose[z;z1] else z←LOSE}
((issub(z)∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
By V5 now: (4)
issub(z)∧mgunified(z;x1;y1)
{C;
z1←unify1[subst[first[x2];z];subst[first[y2];z]]
issub(z1)-IF;
z ← compose[z;z1];}
((issub(z)∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
and (5)
issub(z)∧mgunified(z;x1;y1)
{C;
z1←unify1[subst[first[x2];z];subst[first[y2];z]]
¬issub(z1)-IF
z← LOSE}
((issub(z)∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
(5) is succeptible to V1;
issub(z)∧mgunified(z;x1;y1)
{C;
z1←unify1[subst[first[x2];z];subst[first[y2];z]]
¬issub(z1)-IF
}
((issub(LOSE)∧mgunified(LOSE;concat[first[x2];x1];concat[first[y2];y1]))
∨(LOSE=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
then use V3(iii):
issub(z)∧mgunified(z;x1;y1)
{C;
z1←unify1[subst[first[x2];z];subst[first[y2];z]]
}
¬issub(z1) ⊃
((issub(LOSE)∧mgunified(LOSE;concat[first[x2];x1];concat[first[y2];y1]))
∨(LOSE=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Now V1:
issub(z)∧mgunified(z;x1;y1)
{C;
}
¬issub(unify1[subst[first[x2];z];subst[first[y2];z]])
⊃
((issub(LOSE)∧mgunified(LOSE;concat[first[x2];x1];concat[first[y2];y1]))
∨(LOSE=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Time to look at program's current state without assertions:
{x1←();
x2←x;
y1←();
y2←y;
z←();R(x,x1,x2,y,y1,y2,z);
while ¬empty[x2]∧ ¬empty[y2]∧¬z=LOSE do
[|C;z1←unify1[subst[first[x2];z];subst[first[y2];z]]
if issub(z1) then z ← compose[z;z1] else z←LOSE |]
x1← concat[first[x2];x1]; y1← concat[first[y2];y1];
x2←rest[x2]; y2← rest[y2]}
Looks reasonable: so we continue to thrash (5).
{C} should be {NULL}.
issub(z)∧mgunified(z;x1;y1)
⊃
(¬issub(unify1[subst[first[x2];z];subst[first[y2];z]])
⊃
(¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
What about (4)? since "C" is empty we have:
issub(z)∧mgunified(z;x1;y1)
{z1←unify1[subst[first[x2];z];subst[first[y2];z]]
issub(z1)-IF;
z ← compose[z;z1];}
((issub(z)∧mgunified(z;concat[first[x2];x1];concat[first[y2];y1]))
∨(z=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Using V1:
issub(z)∧mgunified(z;x1;y1)
{z1←unify1[subst[first[x2];z];subst[first[y2];z]]
issub(z1)-IF;
}
((issub(compose[z;z1])∧mgunified(compose[z;z1];concat[first[x2];x1];concat[first[y2];y1]))
∨(compose[z;z1]=LOSE∧¬unifiable(concat[first[x2];x1],concat[first[y2];y1])
)
Using V3(iii) and properties of compose:
issub(z)∧mgunified(z;x1;y1)
{z1←unify1[subst[first[x2];z];subst[first[y2];z]]
}
issub(z1)
⊃
((issub(compose[z;z1])∧mgunified(compose[z;z1];concat[first[x2];x1];concat[first[y2];y1]))
)
And with V1 and V3(i):
issub(z)∧mgunified(z;x1;y1)
⊃
issub(unify1[subst[first[x2];z];subst[first[y2];z]])
⊃
((issub(compose[z; unify1[subst[first[x2];z];subst[first[y2];z]]])
∧mgunified(compose[z;unify1[subst[first[x2];z];subst[first[y2];z]]];
concat[first[x2];x1];
concat[first[y2];y1]))
)
Simplification (assuming issub(z) and issub(unify1..)) and properties of
compose) yields:
mgunified(z;x1;y1) ⊃
mgunified(compose[z;unify1[subst[first[x2];z];subst[first[y2];z]]];
concat[first[x2];x1];
concat[first[y2];y1])))
Now it seems reasonable to go after unify1[x;y] <= ... .
On entry we have: isterm(x) and isterm(y)
On exit the value of unify1(x,y) is LOSE if ¬unifiable(x,y) or
is a substitution which is the m.g.u. of x and y.
Too much pain is inflicted here in having to describe the dispatching
on data-types in terms of conditional expressions.
However...:
_____________________________________
isterm(x) and isterm(y)
{if is_var(x) then B else C}
LOSE if ¬unifiable(x,y) or issub which is the m.g.u. of x and y.